package com.mijie.homi.ns.core;

import java.util.Date;
import java.util.HashMap;

import javax.annotation.PostConstruct;

import org.apache.log4j.Logger;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mijie.homi.common.constant.MCKey;
import com.mijie.homi.common.constant.TypeCode;
import com.mijie.homi.common.protocol.HomiProtocol;
import com.mijie.homi.ns.core.handler.ChatHandler;
import com.mijie.homi.ns.core.handler.Handler;
import com.mijie.homi.ns.core.handler.HeartBeatHandler;
import com.mijie.homi.ns.core.handler.LoginHandler;
import com.mijie.homi.ns.core.handler.LogoutHandler;
import com.mijie.homi.ns.domain.Constants;
import com.mijie.homi.ns.service.MemcacheService;
import com.mijie.homi.ns.service.SessionService;
import com.mijie.homi.ns.service.UserService;
import com.mijie.util.DateUtil;

@Service
public final class HandlerDispatcher extends IoHandlerAdapter {

	private static Logger logger  = Logger.getLogger(HandlerDispatcher.class);
	private HashMap<Short,Handler> handlers = new HashMap<Short,Handler>(5);
	@Autowired
	private UserService userService;
	@Autowired
	private SessionService sessionService;
	@Autowired
	private LoginHandler loginHandler;
	@Autowired
	private LogoutHandler logoutHandler;
	@Autowired
	private ChatHandler chatHandler;
	@Autowired
	private HeartBeatHandler heartBeatHandler;
	@Autowired
	private HomiServer homiServer;
	@Autowired
	private MemcacheService mcs;
	
	@PostConstruct
	private void setup() {
		handlers.put(TypeCode.LOGIN, loginHandler);
		handlers.put(TypeCode.LOGOUT, logoutHandler);
		handlers.put(TypeCode.CHAT, chatHandler);
		handlers.put(TypeCode.HEART_BEAT, heartBeatHandler);
	}

	
	@Override
	public void exceptionCaught(IoSession session, Throwable cause)
			throws Exception {
		logger.error("exceptionCaught[session="+session.getId()+"]-> userId:"+session.getAttribute(Constants.KEY_USER_ID)+" message:"+cause.getMessage(), cause);
		session.close(true);
	}
	
	@Override
	public void sessionOpened(IoSession session) throws Exception {
		Date now = new Date();
		session.setAttribute(Constants.KEY_LAST_ACCESS_AT,now);
		session.setAttribute(Constants.KEY_ONLINE_MINUTE,now);
		userService.incrOnlineUserAmount();
	}

	@Override
	public void sessionClosed(IoSession session) throws Exception {
		userService.decrOnlineUserAmount();
		String token = (String) session.getAttribute(Constants.KEY_TOKEN);
		if(token!=null){
			homiServer.incrOnlineLong(session,false);
			Integer userId = sessionService.getUserIdByToken(token);
			mcs.delete(MCKey.SESSION,token);
			
			if(userId!=null){
				String tokenByUserId = mcs.getString(MCKey.TOKEN_BY_USERID,String.valueOf(userId));
				userService.deleteUserInfoSubcribe(userId);
				if(tokenByUserId!=null && token.equals(tokenByUserId)){
					//tokenByUserId和传过来的token一样，说明是正常下线，否则为被迫下线，被迫下线无需清除以用户ID为KEY的token
					mcs.delete(MCKey.TOKEN_BY_USERID,String.valueOf(userId));
				}
			}
		}
		logger.info("sessionClosed[session="+session.getId()+",amount of session="+session.getService().getManagedSessionCount()+"]-> token:"+token+" userId:"+session.getAttribute(Constants.KEY_USER_ID)+" last_access_at:"+DateUtil.date2str((Date)session.getAttribute(Constants.KEY_LAST_ACCESS_AT),true));
	}

	
	@Override
	public void messageReceived(IoSession session, Object message)
			throws Exception {
		if(message!=null){
			HomiProtocol protocol = (HomiProtocol) message;
			Handler handler = handlers.get(protocol.getType());
			if(handler!=null){
				session.setAttribute(Constants.KEY_LAST_ACCESS_AT, new Date());
				
				if((protocol.getType()!=TypeCode.HEART_BEAT && protocol.getType()!=TypeCode.LOGOUT) 
					&& (protocol.getContent()==null || protocol.getContent().isEmpty()) ){
					return;
				}
//				logger.info("messageReceived[session="+session.getId()+"]->userId:"+session.getAttribute(Constants.KEY_USER_ID)+" type:"+protocol.getType()+" content:"+protocol.getContent()+".");
				handler.handler(session, protocol);
			}
		}
	}

	@Override
	public void messageSent(IoSession session, Object message) throws Exception {
		HomiProtocol protocol = (HomiProtocol) message;
//		logger.info("messageSent[session="+session.getId()+"]->userId:"+session.getAttribute(Constants.KEY_USER_ID)+" type:"+protocol.getType()+" content:"+protocol.getContent());
	}

	@Override
	public void sessionIdle(IoSession session, IdleStatus status)
			throws Exception {
		if(status == IdleStatus.BOTH_IDLE){
//			logger.info("sessionIdle[session="+session.getId()+"]->-userId:"+session.getAttribute(Constants.KEY_USER_ID));
			session.close(true);
		}
	}
	
	
	
}
